//======================================================================================================================
// 2007 Copyright Mystic Lake Software
//
// This file is part of The Ham Radio Network.
//
// The Ham Radio Network is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// The Ham Radio Network is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//======================================================================================================================
//
//     Author: Rudyard Merriam
//
//      $Id: PRBSScrambler.cpp 6 2007-10-04 07:01:34Z k5rud@arrl.net $
//
//======================================================================================================================
//
#include <iostream>
#include <bitset>

using namespace std;

typedef bitset<8> Bitset8;

static const size_t prbs_taps = 3; static const size_t prbs_size = 8; static const size_t t1 = 0; static const size_t t2 = 2;
//static const size_t prbs_taps = 11; static const size_t prbs_size = 2047; static const size_t t1 = 1; static const size_t t2 = 10;
static const size_t prbs_init = 0x55;
//==========================================================================================================================
template <size_t SIZE, size_t TAPS, size_t INIT=prbs_init>
class PrbsScrambler
{
public:
    void scramble(const Bitset8& in, Bitset8& out);
    void descramble(const Bitset8& in, Bitset8& out);

    static const size_t length = SIZE;

protected:
    static const size_t tap1 = t1;
    static const size_t tap2 = t2;
    static const size_t taps = TAPS;
};
//--------------------------------------------------------------------------------------------------------------------------
template <size_t SIZE, size_t TAPS, size_t INIT>
void PrbsScrambler<SIZE, TAPS, INIT>::scramble(const Bitset8& in, Bitset8& out)
{
    bitset<taps> t(INIT);
    bool feedback = false;

    for(size_t pos = 0; pos < length; pos++)
    {
        bool bit = in[pos];
        feedback = t[tap1] ^ t[tap2];

        bit ^= feedback;
        out[pos] = bit;

        for (size_t tap = taps-1; tap > 0; tap--)
        {
            t[tap] = t[tap-1];
        }
        t[0] = bit;
    }
}
//--------------------------------------------------------------------------------------------------------------------------
template <size_t SIZE, size_t TAPS, size_t INIT>
void PrbsScrambler<SIZE, TAPS, INIT>::descramble(const Bitset8& in, Bitset8& out)
{
    bitset<taps> t(INIT);
    bool output = false;

    for(size_t pos = 0; pos < length; pos++)
    {
        bool bit = in[pos];
        output = t[tap1] ^ t[tap2];

        out[pos] = output ^ bit;

        for (size_t tap = taps-1; tap > 0; tap--)
        {
            t[tap] = t[tap-1];
        }
        t[0] = bit;
    }
}
typedef PrbsScrambler<prbs_size, prbs_taps> Scrambler;
//==========================================================================================================================
int main(int argc, char *argv[ ])
{
    Bitset8 in;
    if (argc == 2)
    {
        if (argv[1][0] == 'E')
            while (!cin.eof())
            {
                cin >> in;
                if (cin.good())
                {
                    Bitset8 out;    
                    Scrambler scrambler;
                    scrambler.scramble(in, out);
                    cout << out << endl;
                }
            } 
        else if (argv[1][0] == 'D')
        {
            while (!cin.eof())
            {
                cin >> in;
                if (cin.good())
                {
                    Bitset8 out;    
                    Scrambler scrambler;
                    scrambler.descramble(in, out);
                    cout << out;
                }
            } 
        }
    }
    else
    {
        cerr << "(E)ncode or (D)ecode option missing" << endl;
    }
}

